package org.yscz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yscz.bs.lib.InquestControlOuterClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.yscz.common.ViewConfig;
import org.yscz.common.enums.AlgResponseEnum;
import org.yscz.common.enums.MediaResponseEnum;
import org.yscz.entity.Answer;
import org.yscz.entity.Record;
import org.yscz.entity.RoomBean;
import org.yscz.entity.vo.QuestionVo;
import org.yscz.entity.vo.RecordVo;
import org.yscz.entity.vo.ScaleVo;
import org.yscz.entity.vo.TesteeVo;
import org.yscz.exception.AlgAnalysisException;
import org.yscz.exception.MediaCommandException;
import org.yscz.mapper.AnswerMapper;
import org.yscz.mapper.QuestionMapper;
import org.yscz.mapper.RecordMapper;
import org.yscz.service.EvaluationService;
import org.yscz.media.MediaService;
import org.yscz.service.ScaleService;
import org.yscz.service.TesteeService;
import org.yscz.task.ApplicationRunnerImpl;
import org.yscz.webSocket.service.impl.WebSocketServiceImpl;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 开始测评
 *
 * @author achen
 * @create 2021-08-19 15:37
 */
@Service
@Slf4j
public class EvaluationServiceImpl implements EvaluationService {

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    @Value("${yscz.usbDevice.enable:true}")
    private boolean usbEnable;

    @Autowired
    private MediaService mediaService;

    @Autowired
    private TesteeService testeeService;

    @Autowired
    private ScaleService scaleService;

    @Resource
    private RecordMapper recordMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AnswerMapper answerMapper;

    @Resource
    private QuestionMapper questionMapper;

    /**
     * 开始测评
     *
     * @param roomBean 封装算法数据
     */
    @Override
    public void startEvaluation(RoomBean roomBean, Boolean flag) throws AlgAnalysisException, MediaCommandException {
        // 判断是否正在分析
        if (NotifyAlgBusiness.startReply != null && NotifyAlgBusiness.getAnalyzingRoomBean() != null) {
            //throw new AlgAnalysisException(AlgResponseEnum.ALG_BEING_ANALYSIS_ERROR);
            endEvaluation(NotifyAlgBusiness.getAnalyzingRoomBean());
        }

        // usb 摄像头推流
        if (usbEnable) {
            int result = mediaService.pushUsbStream(roomBean);
            if (result < 0) {
                throw new MediaCommandException(MediaResponseEnum.MEDIA_PUSH_USB_STREAM_FAIL);
            }
        }
        //添加流代理
        //mediaService.addStream(roomBean);

        if (flag) {
            // 开始分析
            InquestControlOuterClass.StartReply startReply = NotifyAlgBusiness.notifyAlgStartAnalyze(roomBean);
            if (startReply == null) {
                //算法异常 关闭视频流
                mediaService.delSteam(roomBean.getUuid());
                if (usbEnable) {
                    int result = mediaService.stopUsbStream();
                    if (result < 0) {
                        throw new MediaCommandException(MediaResponseEnum.MEDIA_STOP_USB_STREAM_FAIL);
                    }
                }
                throw new AlgAnalysisException(AlgResponseEnum.ALG_START_ANALYSIS_FAIL);
            }
        }
    }

    @Override
    public void endEvaluation(RoomBean roomBean) throws AlgAnalysisException {
        try {
            log.info("roomBean:[{}]", roomBean);
            if (NotifyAlgBusiness.startReply != null && NotifyAlgBusiness.getAnalyzingRoomBean() != null) {
                if (!NotifyAlgBusiness.isAnalyzingRoomBean(roomBean.getUuid())) {
                    throw new AlgAnalysisException(AlgResponseEnum.ALG_NOT_BEING_ANALYSIS_ERROR);
                }
            }
            //通知算法结束
            EvaluationServiceImpl.NotifyAlgBusiness.notifyAlgStopAnalyze(roomBean.getUuid());
            //结束测评 关闭流媒体流
            //int delSteamResult = mediaService.delSteam(roomBean.getUuid());
            if (usbEnable) {
                int stopUsbResult = mediaService.stopUsbStream();
            }

            //清空折线图数据 防止算法没关闭webSocket一直推送 如果继续测评需要展示 去数据库查出该条测评记录
            stringRedisTemplate.delete(roomBean.getUuid());
            stringRedisTemplate.delete(WebSocketServiceImpl.recordUuid + "_time");
            stringRedisTemplate.delete(WebSocketServiceImpl.recordUuid + "_question");
        } finally {
            ViewConfig.exceptionEmotionTotalNum.set(0);           // 异常表情次数为空
            ViewConfig.exceptionQuestionTotalNum.set(0);        //异常题目数量
            ViewConfig.everyQuestionExceptionNum.set(0);
            ViewConfig.everyMinuteExceptionNum.set(0);
            ViewConfig.currentQuestIndex.set(1);
            ViewConfig.minuteNum.set(0);
            ViewConfig.abnormalEmotionList.clear();
            ViewConfig.lessThanAbnormalNum = 0;
            WebSocketServiceImpl.timeJSONArray.clear();
            WebSocketServiceImpl.questJSONArray.clear();
        }
    }

    @Override
    public JSONObject getEvalInfos(JSONObject dataObj) {

        Long testeeId = dataObj.getLong("testeeId");
        Long userId = dataObj.getLong("userId");
        Long scaleId = dataObj.getLong("scaleId");
        Long recordId = dataObj.getLong("recordId");

        Map condition = new HashMap();
        JSONObject resultObj = new JSONObject();

        // 被测人信息
        TesteeVo testeeVo = testeeService.testeeDetail(testeeId);
        resultObj.put("testeeInfo", testeeVo);

        // 量表信息
        ScaleVo scaleVo = scaleService.queryScaleDetail(scaleId);
        resultObj.put("scaleInfo", scaleVo);

        // 题目信息
        List<QuestionVo> questionList = scaleService.queryByScaleId(scaleId);
        resultObj.put("questionInfo", questionList);

        // 继续测评时，测评记录信息,更新开始测评时间
        Record currentRecordInfo = new Record();
        if (recordId != null) {
            // modify by muqs 2021-09-18
            currentRecordInfo = recordMapper.selectById(recordId);
//            condition.put("recordStartTime", currentRecordInfo.getRecordStartTime());
//            String recordCreatetime = StringUtils.isNotEmpty(currentRecordInfo.getRecordCreateTime()) ? currentRecordInfo.getRecordCreateTime() + "," + sdf.format(new Date()) : sdf.format(new Date());
//            currentRecordInfo.setRecordCreateTime(recordCreatetime);
//            recordMapper.updateById(currentRecordInfo);
        } else {
            //String uuid = UUID.randomUUID().toString();
            //currentRecordInfo.setRecordUuid(ApplicationRunnerImpl.algUuid);
            currentRecordInfo.setRecordTesteeName(testeeVo.getTesteeName());
            currentRecordInfo.setSex(testeeVo.getSex());
            currentRecordInfo.setAge(testeeVo.getAge());
            currentRecordInfo.setStatus(0);
            currentRecordInfo.setQuestionNum(1);
            Date startTime = new Date();
            currentRecordInfo.setRecordStartTime(startTime);
            currentRecordInfo.setScaleIdFk(scaleId);
            // 设置测评人ID
            currentRecordInfo.setUserIdFk(userId);
            currentRecordInfo.setTesteeGroupIdFk(testeeVo.getTesteeGroupIdFk());
//        currentRecordInfo.setUserIdFk()
            currentRecordInfo.setTesteeIdFk(testeeId);
            recordMapper.insert(currentRecordInfo);
            dataObj.put("recordId", currentRecordInfo.getRecordId());
        }

        // 上次测评记录
        condition.put("testeeId", testeeId);
        condition.put("status", 1);
        RecordVo previousRecordInfo = recordMapper.queryPreviousRecordInfo(condition);
        condition.clear();

        resultObj.put("previousRecordInfo", previousRecordInfo);
        resultObj.put("currentRecordInfo", currentRecordInfo);
        // 答题进度
        Integer answerProgress = answerMapper.selectAnswerProgress(recordId);
        resultObj.put("answerProgress", answerProgress != null ? answerProgress : 0);

        // 查询测评记录，将试题信息正在答题信息推送主屏
        condition.put("scaleId", currentRecordInfo.getScaleIdFk());
        condition.put("questionNum", currentRecordInfo.getQuestionNum());
        QuestionVo questionVo = questionMapper.queryDetailById(condition);
        dataObj.put("questionInfo", questionVo);

        // 当前进度题目信息
        QueryWrapper currentAnswerWrappeer = new QueryWrapper<>();
        currentAnswerWrappeer.eq("record_id_fk", currentRecordInfo.getRecordId());
        currentAnswerWrappeer.eq("answer_question_num", currentRecordInfo.getQuestionNum());
        Answer currentAnswer = answerMapper.selectOne(currentAnswerWrappeer);
        dataObj.put("answer", currentAnswer);

        // 答题总时长
        Integer answerTotalTime = answerMapper.sumDuration(currentRecordInfo.getRecordId());
        dataObj.put("answerTotalTime", answerTotalTime != null ? answerTotalTime : 0);

        // 异常表情次数，
        dataObj.put("exceptionFaceNum", currentRecordInfo.getExceptionSumNum());
        // 异常表情答题数
        dataObj.put("exceptionQuestionNum", currentRecordInfo.getExceptionQuestionSumNum());

        // 问题折线图数据（数组）
        dataObj.put("questLine", StringUtils.isNotEmpty(currentRecordInfo.getQuestionLine()) ? JSONObject.parseArray(currentRecordInfo.getQuestionLine()) : new ArrayList());
        // 时间折线图数据（数组）
        dataObj.put("timeLine", StringUtils.isNotEmpty(currentRecordInfo.getTimeLine()) ? JSONObject.parseArray(currentRecordInfo.getTimeLine()) : new ArrayList());

        dataObj.put("evalInfo", resultObj);
        return dataObj;
    }


    /**
     * 算法交互封装的内部类
     */
    public static class NotifyAlgBusiness {

        private static RoomBean analyzingRoomBean;      //正在分析的roomBean
        private static InquestControlOuterClass.StartReply startReply;

        //通知算法开始分析
        public static InquestControlOuterClass.StartReply notifyAlgStartAnalyze(RoomBean roomBean) {
            try {
                if (startReply != null) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("uuid", roomBean.getUuid());
                    if (notifyAlgStopAnalyze(roomBean.getUuid()) != null) {
                        startReply = null;
                    }
                }
                log.info("begin to notifyAlgAnalyze");
                startReply = ApplicationRunnerImpl.inquestConfig.startInquest(roomBean);
                analyzingRoomBean = roomBean;
            } catch (Exception e) {
                log.error("notifyAlgAnalyze error [{}]", e.getMessage());
            }
            return startReply;
        }

        // 通知算法结束分析
        public static InquestControlOuterClass.TerminateReply notifyAlgStopAnalyze(String uuid) {
            log.info("notifyAlgStopAnalyze [{}]", uuid);
            InquestControlOuterClass.TerminateReply terminateReply = null;
            try {
                Map<String, Object> map = new HashMap<>();
                map.put("uuid", uuid);
                map.put("userId", "111");
                terminateReply = ApplicationRunnerImpl.inquestConfig.terminateInquest(map);
                if (terminateReply != null) {
                    startReply = null;
                    analyzingRoomBean = null;
                }
            } catch (Exception e) {
                log.error("notifyAlgStopAnalyze error [{}]", e.getMessage());
            }
            return terminateReply;
        }

        public static RoomBean getAnalyzingRoomBean() {
            return analyzingRoomBean;
        }

        /**
         * 判断是否正在分析
         *
         * @param uuid
         * @return
         */
        public static boolean isAnalyzingRoomBean(String uuid) {
            if (getAnalyzingRoomBean() == null) {
                return false;
            }
            return StringUtils.isNotEmpty(uuid) && getAnalyzingRoomBean().getUuid().equals(uuid);
        }
    }
}
